
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>模拟 Mac OS 窗口最小化的神奇效果</title>
<meta name="description" content="模拟 Mac OS 窗口最小化的神奇效果（阿拉丁神灯）" />
<meta name="author" content="impony.com" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style type="text/css">
html,body{margin:0;padding:0;height:100%;background:#69C;font:14px/1.5 sans-serif;}
.window{border:1px solid #888;background:#FFF;box-shadow:0 0 2em rgba(0, 0, 0, .3);}
.window>.t{margin:0;padding:.3em;border-bottom:1px solid #888;background:#CCC;}
.window>.c{padding:.3em;min-height:15em;}
footer{position:absolute;top:0;left:0;width:100%;height:3em;background:rgba(0, 0, 0, .2);}
.dock{display:inline-block;margin:.3em;width:5em;height:2.4em;line-height:2.4em;text-align:center;color:#FFF;background:rgba(0, 0, 0, .6);cursor:pointer;}
.dock:first-child{margin-right:0;}
.folded{background:rgba(0, 0, 0, .3);}
footer>span:last-child{color:#69C;}
#w0_window{position:absolute;left:5%;top:10%;width:60%;height:70%;}
#w1_window{position:absolute;right:0%;top:40px;width:100%;height:50%;}
.canvas{position:absolute;z-index:-1;transform: rotateX(180deg);}
</style>
</head>
<body>

<div id="w1_window" class="window">
	<h3 class="t">窗口二</h3>
	<div class="c">窗口中的内容</div>
</div>
<footer>
	<span id="w1" class="dock" lock="false" style="margin-left: 50px;">窗口二</span>
	
</footer>
<canvas class="canvas"></canvas>

<script type="text/javascript">
(function () {
	"use strict";
	var canvas = document.querySelector("canvas");
	var ctx = canvas.getContext("2d");
	/**
	 * 绘制形状
	 * @param s1 {Number} 起点一
	 * @param s2 {Number} 起点二
	 * @param p1 {Number} 结束点一
	 * @param p2 {Number} 结束点二
	 */
	function draw(s1, s2, p1, p2) {
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		ctx.beginPath();
		ctx.moveTo(s1, 0);
		ctx.bezierCurveTo(s1, canvas.height * 0.2, p1, canvas.height * 0.6, p1, canvas.height);
		ctx.lineTo(p2, canvas.height);
		ctx.bezierCurveTo(p2, canvas.height * 0.6, s2, canvas.height * 0.2, s2, 0);
		ctx.lineTo(s1, 0);
		ctx.fillStyle = "rgba(0, 0, 0, .2)";
		ctx.fill();
	}
	/**
	 * 擦除方式
	 * @param y {Number}
	 * @param speed {Number}
	 * @param type 类型，放大或缩小 zoomin、zoomout
	 */
	function clearRect(y, speed, type) {
		if(type === "zoomout") {
			ctx.clearRect(0, y, canvas.width, speed);
		} else if(type === "zoomin") {
			ctx.clearRect(0, 0, canvas.width, y);
		}
	}
	/**
	 * 缩放效果
	 * @param s1 {Number} 起点一
	 * @param s2 {Number} 起点二
	 * @param p1 {Number} 结束点一
	 * @param p2 {Number} 结束点二
	 * @param type {String} 类型，放大或缩小 zoomin、zoomout
	 */
	function scale(s1, s2, p1, p2, type, callback) {
		var dist1 = Math.abs(p1 - s1);
		var dist2 = Math.abs(p2 - s2);
		var d1, d2, _p1, _p2, speed1, y, speed2;
		if(dist1 === 0 || dist2 === 0) {
			dist1 = 1;
			dist2 = 1;
		}
		speed1 = 30;
		speed2 = 30;
		if(type === "zoomout") {
			d1 = (p1 >= s1 && p1 < speed1) ? 0 : p1 < s1 ? -speed1 : speed1;
			d2 = p2 < s2 ? -speed1 * dist2 / dist1 : speed1 * dist2 / dist1;
			_p1 = s1;
			_p2 = s2;
			y = 0;
			var t = setInterval(function () {
				if(_p2 - _p1 <= p2 - p1) {
					clearInterval(t);
					var timer = setInterval(function () {
						if(y > canvas.height) {
							clearInterval(timer);
							callback && callback();
						}
						clearRect(y, speed2, type);
						y += speed2;
						speed2 += 1;
					}, 17);
				}
				draw(s1, s2, _p1, _p2);
				_p1 += d1;
				_p2 += d2;
				if((d1 < 0 && _p1 <= p1) || (d1 > 0 && _p1 >= p1)) {
					_p1 = p1;
				}
				if((d2 < 0 && _p2 <= p2) || (d2 > 0 && _p2 >= p2)) {
					_p2 = p2;
				}
			}, 17);
		} else if(type === "zoomin") {
			d1 = (p1 >= s1 && p1 < speed1) ? 0 : p1 < s1 ? speed1 : -speed1;
			d2 = p2 < s2 ? speed1 * dist2 / dist1 : -speed1 * dist2 / dist1;
			_p1 = p1;
			_p2 = p2;
			y = canvas.height;
			var timer = setInterval(function () {
				if(y <= 0) {
					clearInterval(timer);
					var t = setInterval(function () {
						if(_p2 - _p1 >= s2 - s1) {
							clearInterval(t);
							callback && callback();
						}
						draw(s1, s2, _p1, _p2);
						_p1 += d1;
						_p2 += d2;
					}, 17);
				}
				draw(s1, s2, _p1, _p2);
				clearRect(y, speed2, type);
				y -= speed2;
				speed2 += 1;
			}, 17);
		}
	}
	document.addEventListener("DOMContentLoaded", function () {
		var docks = document.querySelectorAll(".dock");
		if(docks && docks.length > 0) {
			for(var i = 0, len = docks.length; i < len; i++) {
				docks[i].addEventListener("click", function () {
					if(this.getAttribute("lock") === "false") {
						var win = document.getElementById(this.id + "_window");
						var _this = this;
						_this.setAttribute("lock", "true");
						canvas.width = document.body.offsetWidth;
						canvas.height = _this.parentNode.offsetTop - win.offsetTop;
						canvas.style.top = win.offsetTop + "px";
						canvas.style.zIndex = 1;
						win.style.visibility = "hidden";
						var s1 = win.offsetLeft;
						var s2 = win.offsetLeft + win.offsetWidth;
						var p1 = _this.offsetLeft;
						var p2 = _this.offsetLeft + _this.offsetWidth;
						var cname = _this.className;
						if(cname.indexOf(" folded") === -1) {
							scale(s1, s2, p1, p2, "zoomout", function () {
								canvas.style.zIndex = -1;
								_this.setAttribute("lock", "false");
							});
							_this.className = cname + " folded";
						} else {
							scale(s1, s2, p1, p2, "zoomin", function () {
								canvas.style.zIndex = -1;
								win.style.visibility = "visible";
								_this.setAttribute("lock", "false");
							});
							_this.className = cname.replace(" folded", "");
						}
					}
				}, false);
			}
		}
	}, false);
})();
</script>

</body>
</html>